/* 
 * File:   SuperState.h
 * Author: Hadrien
 *
 * Created on 11 juillet 2012, 13:18
 */

#ifndef SUPERSTATE_H
#define	SUPERSTATE_H

template<typename STATE, typename OBSERVATION, typename ACTION>
class SuperState {
public:
    typedef STATE state_t;
    typedef OBSERVATION obs_t;
    typedef ACTION action_t;
    SuperState(){
        //Array initialization to zero
        for(int s_index = 0; s_index < state_t::size; s_index++){
            for(int a_index = 0; a_index < action_t::size; a_index++){
                for(int ss_index = 0; ss_index < state_t::size; ss_index++){
                    m_countTransitions[s_index][a_index][ss_index] = 0;
                }
            }
        }
        for(int s_index = 0; s_index < state_t::size; s_index++){
            for(int a_index = 0; a_index < action_t::size; a_index++){
                for(int z_index = 0; z_index < obs_t::size; z_index++){
                    m_countObservations[s_index][a_index][z_index] = 0;
                }
            }
        }
    }
    
    SuperState(const state_t& state){
        m_state = state;
        //Array initialization to zero
        for(int s_index = 0; s_index < state_t::size; s_index++){
            for(int a_index = 0; a_index < action_t::size; a_index++){
                for(int ss_index = 0; ss_index < state_t::size; ss_index++){
                    m_countTransitions[s_index][a_index][ss_index] = 0;
                }
            }
        }
        for(int s_index = 0; s_index < state_t::size; s_index++){
            for(int a_index = 0; a_index < action_t::size; a_index++){
                for(int z_index = 0; z_index < obs_t::size; z_index++){
                    m_countObservations[s_index][a_index][z_index] = 0;
                }
            }
        }
    }
    
    virtual ~SuperState(){
        
    }
    
    // Overload equal to operator
    bool operator==(SuperState const &s1, SuperState const& s2){
        
        bool b1 = (s1.m_state.index() == s2.m_state.index());
        
        bool b2 = true;
        
        for(int s_index = 0; s_index < state_t::size; s_index++){
            for(int a_index = 0; a_index < action_t::size; a_index++){
                for(int ss_index = 0; ss_index < state_t::size; ss_index++){
                    
                    b2 = (b2 && (s1.m_countTransitions[s_index][a_index][ss_index] == s2.m_countTransitions[s_index][a_index][ss_index]));
                    
                }
            }
        }
        
        bool b3 = true;
        
        for(int s_index = 0; s_index < state_t::size; s_index++){
            for(int a_index = 0; a_index < action_t::size; a_index++){
                for(int z_index = 0; z_index < obs_t::size; z_index++){
                    
                    b3 = (b3 && s1.m_countObservations[s_index][a_index][z_index] == s2.m_countObservations[s_index][a_index][z_index]); 
                    
                }
                
            }
        }
        
        return (b1 && b2 && b3);
        
    
    }
    
    bool operator!=(SuperState const &s1, SuperState const& s2){
     
        return !(s1 == s2);
        
    }

    
    //Overload comparison to be used in a belief
    bool operator<(SuperState const &s1, SuperState const& s2){
        if(s1.m_state.index()<s2.m_state.index()){
            return true;
        } else if(s2.m_state.index()<s1.m_state.index()) {
            return false;
        } else {
            for(int s_index = 0; s_index < state_t::size; s_index++){
                for(int a_index = 0; a_index < action_t::size; a_index++){
                    for(int ss_index = 0; ss_index < state_t::size; ss_index++){
                        if (s1.m_countTransitions[s_index][a_index][ss_index] < s2.m_countTransitions[s_index][a_index][ss_index]){
                            return true;
                        } else if (s2.m_countTransitions[s_index][a_index][ss_index] < s1.m_countTransitions[s_index][a_index][ss_index]){
                            return false;
                        }
                    }
                }
            }
            for(int s_index = 0; s_index < state_t::size; s_index++){
                for(int a_index = 0; a_index < action_t::size; a_index++){
                    for(int z_index = 0; z_index < obs_t::size; z_index++){
                        if (s1.m_countObservations[s_index][a_index][z_index] < s2.m_countObservations[s_index][a_index][z_index]){
                            return true;
                        } else if (s2.m_countObservations[s_index][a_index][z_index] < s1.m_countObservations[s_index][a_index][z_index]){
                            return false;
                        }
                    }
                }
            }
            return false;
        }
    }
    
    state_t getState() const {
        return m_state;
    }
    
/*    SuperState update(const action_t& a, int ss, const obs_t& z) const{
        SuperState newSuperState(this);
        newSuperState.m_countObservations[m_state.index()][a.index()][z.index()]++;
        newSuperState.m_countTransitions[m_state.index()][a.index()][ss]++;
    } 
*/    
    SuperState update(int a, int ss, int z) const{
        SuperState newSuperState(this);
        newSuperState.m_countObservations[m_state.index()][a][z]++;
        newSuperState.m_countTransitions[m_state.index()][a][ss]++;
    } 
    
/*    SuperState getT(const state_t& s, const action_t& a, const state_t& ss) const{
        double r = 0;
        for(int i=0;i<state_t::size;i++){
            r += m_countTransitions[s.index()][a.index()][i];
        }
        r = m_countTransitions[s.index()][a.index()][ss.index()]/r;
    }
**/    
    double getT(int s, int a, int ss) const{
        double r = 0;
        for(int i=0;i<state_t::size;i++){
            r += m_countTransitions[s][a][i];
        }
        r = m_countTransitions[s][a][ss]/r;
    }
    
    double getO(int s, int a, int z) const{
        double r = 0;
        for(int i=0;i<obs_t::size;i++){
            r += m_countObservations[s][a][i];
        }
        r = m_countObservations[s][a][z]/r;
    }
    
private:
    state_t m_state;
    int m_countTransitions[state_t::size][action_t::size][state_t::size];
    int m_countObservations[state_t::size][action_t::size][obs_t::size];
};

#endif	/* SUPERSTATE_H */

